package com.hqyj.service.impl;

import com.hqyj.pojo.R;
import com.hqyj.service.OrderRedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class OrderRedisServiceImpl implements OrderRedisService {

    @Autowired
    RedisTemplate<String,Object> redisTemplate;
    @Override
    public R orderCreate(Integer shopId, Integer num) {
        //1 查询库存，存入redis缓存中
        String key ="shop:"+shopId;
        //获取库存
        Object obj  = redisTemplate.opsForValue().get(key);
        if(obj==null){
            redisTemplate.opsForValue().set(key,10,15, TimeUnit.MINUTES);
        }
        //值要唯一，是为了释放锁，保证每个线程正确释放锁，防治误删
        String uuid = UUID.randomUUID()+"";
        //获取锁
        Boolean is = getLock(shopId,uuid);
        //获取线程id
        Long id = Thread.currentThread().getId();
        //如果是is 是false,其他线程已经占用了，该线程排队
        if(!is){
            log.info("线程:"+id+"没有获取到锁，排队中");
            try{
                while (!getLock(shopId,uuid)){
                    //让当前线程睡眠，和其他线程的业务错开
                    Thread.sleep(1000);
                }
            }catch (Exception e){
                log.info("出现异常");
                e.printStackTrace();
            }
        }
        //-------------获取到锁的业务--------------------
        try {
            log.info("线程:"+id+"获取到了锁，开始处理业务");
            //判断库存是否大于0
            Integer stockNum = (Integer) redisTemplate.opsForValue().get(key);
            if(stockNum<=0){
                log.info("线程:"+id+"没有抢购到商品");
                return R.error("商品卖完，没有抢购到商品");
            }
            Integer newStockNum = stockNum-num;
            if(newStockNum<0){
                log.info("线程:"+id+"够买得商品数量不足");
                return R.error("商品库存只有"+stockNum+"个，你购物的数量不够");
            }
            log.info("线程:"+id+"抢购到商品了");
            //更新库存
            redisTemplate.opsForValue().set(key,newStockNum);
            //调用订单新增业务
        }catch (Exception e){
            e.printStackTrace();
            log.info("够买商品出现异常");
        }finally {
            /*------释放锁------*/
            String lockKey = "suo:"+shopId;
            if(redisTemplate.opsForValue().get(lockKey).equals(uuid)){
                    //删除键
                log.info("线程;"+id+"释放了锁");
                redisTemplate.delete(lockKey);
            }
        }
        return R.ok();
    }

    //创建锁
    public Boolean getLock(Integer shopId,String uuid){
        String key = "suo:"+shopId;
        //为什么要用失效时间：是为了意外情况导致一直被锁
        return redisTemplate.opsForValue().setIfAbsent(key,uuid,15,TimeUnit.MINUTES);


    }
}
